/**
* \file flash.c
* \brief 
*	
*	2.2020-01-16,
*   改为通用文件
* \author mirlee
* \version 0.2
* \date 2019-08-02
*/
#include "boot_drv.h"


//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0     ((unsigned long)0x08000000) 	//扇区0起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_1     ((unsigned long)0x08004000) 	//扇区1起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_2     ((unsigned long)0x08008000) 	//扇区2起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_3     ((unsigned long)0x0800C000) 	//扇区3起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_4     ((unsigned long)0x08010000) 	//扇区4起始地址, 64 Kbytes  
#define ADDR_FLASH_SECTOR_5     ((unsigned long)0x08020000) 	//扇区5起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_6     ((unsigned long)0x08040000) 	//扇区6起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_7     ((unsigned long)0x08060000) 	//扇区7起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_8     ((unsigned long)0x08080000) 	//扇区8起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_9     ((unsigned long)0x080A0000) 	//扇区9起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_10    ((unsigned long)0x080C0000) 	//扇区10起始地址,128 Kbytes  
#define ADDR_FLASH_SECTOR_11    ((unsigned long)0x080E0000) 	//扇区11起始地址,128 Kbytes 

#define ADDR_FLASH_SECTOR_12	((unsigned long)0x08100000) 	//扇区12起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_13	((unsigned long)0x08104000) 	//扇区13起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_14    ((unsigned long)0x08108000) 	//扇区14起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_15	((unsigned long)0x0810C000) 	//扇区15起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_16    ((unsigned long)0x08110000) 	//扇区16起始地址, 64 Kbytes  
#define ADDR_FLASH_SECTOR_17	((unsigned long)0x08120000) 	//扇区17起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_18	((unsigned long)0x08140000) 	//扇区18起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_19	((unsigned long)0x08160000) 	//扇区19起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_20    ((unsigned long)0x08180000) 	//扇区20起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_21	((unsigned long)0x081A0000) 	//扇区21起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_22    ((unsigned long)0x081C0000) 	//扇区22起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_23    ((unsigned long)0x081E0000) 	//扇区23起始地址, 128 Kbytes   

/** @defgroup FLASH_Sectors
  * @{
  */ 
#define FLASH_Sector_0     ((unsigned short)0x0000) /*!< Sector Number 0 */
#define FLASH_Sector_1     ((unsigned short)0x0008) /*!< Sector Number 1 */
#define FLASH_Sector_2     ((unsigned short)0x0010) /*!< Sector Number 2 */
#define FLASH_Sector_3     ((unsigned short)0x0018) /*!< Sector Number 3 */
#define FLASH_Sector_4     ((unsigned short)0x0020) /*!< Sector Number 4 */
#define FLASH_Sector_5     ((unsigned short)0x0028) /*!< Sector Number 5 */
#define FLASH_Sector_6     ((unsigned short)0x0030) /*!< Sector Number 6 */
#define FLASH_Sector_7     ((unsigned short)0x0038) /*!< Sector Number 7 */
#define FLASH_Sector_8     ((unsigned short)0x0040) /*!< Sector Number 8 */
#define FLASH_Sector_9     ((unsigned short)0x0048) /*!< Sector Number 9 */
#define FLASH_Sector_10    ((unsigned short)0x0050) /*!< Sector Number 10 */
#define FLASH_Sector_11    ((unsigned short)0x0058) /*!< Sector Number 11 */

/** @defgroup FLASH_Program_Parallelism   
  * @{
  */
#define FLASH_PSIZE_BYTE           ((uint32_t)0x00000000)
#define FLASH_PSIZE_HALF_WORD      ((uint32_t)0x00000100)
#define FLASH_PSIZE_WORD           ((uint32_t)0x00000200)
#define FLASH_PSIZE_DOUBLE_WORD    ((uint32_t)0x00000300)
#define CR_PSIZE_MASK              ((uint32_t)0xFFFFFCFF)
#define SECTOR_MASK                ((uint32_t)0xFFFFFF07)

//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~11,即addr所在的扇区

unsigned char mbl_get_flash_sector(unsigned long addr)
{
	if(addr<ADDR_FLASH_SECTOR_1)return FLASH_Sector_0;
	else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_Sector_1;
	else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_Sector_2;
	else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_Sector_3;
	else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_Sector_4;
	else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_Sector_5;
	else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_Sector_6;
	else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_Sector_7;
	else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_Sector_8;
	else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_Sector_9;
	else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_Sector_10; 
	else if(addr<ADDR_FLASH_SECTOR_12)return FLASH_Sector_11; 
	else while(1);
}


/**
 * @brief mbl_flash_erase
 * @note 在指定位置开始以字为单位写入flash
 * @param appAdr,程序的开始地址及大小
 *				size  ,bin文件大小
 * @retval -1,error
 */
typedef enum
{ 
  FLASH_BUSY = 1,
  FLASH_ERROR_PG,
  FLASH_ERROR_WRP,
  FLASH_COMPLETE,
  FLASH_TIMEOUT
}FLASH_Status;

int FLASH_GetBank1Status(void)
{
  int flashstatus = FLASH_COMPLETE;
  
  if((FLASH->SR & FLASH_FLAG_BANK1_BSY) == FLASH_FLAG_BSY) 
  {
    flashstatus = FLASH_BUSY;
  }
  else 
  {  
    if((FLASH->SR & FLASH_FLAG_BANK1_PGERR) != 0)
    { 
      flashstatus = FLASH_ERROR_PG;
    }
    else 
    {
      if((FLASH->SR & FLASH_FLAG_BANK1_WRPRTERR) != 0 )
      {
        flashstatus = FLASH_ERROR_WRP;
      }
      else
      {
        flashstatus = FLASH_COMPLETE;
      }
    }
  }
  /* Return the Flash Status */
  return flashstatus;
}
int mbl_flash_erase(unsigned long appAdr, unsigned long size)
{
	
	if((appAdr<0X08000000)||appAdr>(0X08000000+MBL_FLASH_SIZE)||size<=0||size>((0X08000000+MBL_FLASH_SIZE)-appAdr))
		return -1;
	/*clear PG */
	CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
	while(FLASH_GetBank1Status()!=FLASH_COMPLETE){}
#if (STM32F103x||STM32F030x)
	int i=0;
	unsigned long adr;
	while(size>MBL_FLASH_PAGE_SIZE*i)
	{
		adr=appAdr+i*MBL_FLASH_PAGE_SIZE;
		i++;
		/* Proceed to erase the page */
		SET_BIT(FLASH->CR, FLASH_CR_PER);
		WRITE_REG(FLASH->AR, adr);
		SET_BIT(FLASH->CR, FLASH_CR_STRT);
		//while(!FLASH_GET_FLAG(FLASH_FLAG_EOP)){}
		while(FLASH_GetBank1Status()!=FLASH_COMPLETE);
		CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
		if(*(__IO unsigned long*)(adr)!=0xffffffff)
			return MBL_FLASH_ERASE_ERROR;
	}
#elif STM32F429x
  unsigned long start_sector = FLASH_Sector_1;
	unsigned long end_sector = FLASH_Sector_1;
	
  /* Get the sector where start the user flash area */
  start_sector = mbl_get_flash_sector(appAdr);
	end_sector = mbl_get_flash_sector(appAdr+size);
  for (int i = start_sector; i <= end_sector; i += 8)
  {
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
       be done by word */
    uint32_t tmp_psize = 0x0;
    tmp_psize = FLASH_PSIZE_WORD;
		while(FLASH_GetBank1Status()!=FLASH_COMPLETE){}		
    /* if the previous operation is completed, proceed to erase the sector */
    FLASH->CR &= CR_PSIZE_MASK;
    FLASH->CR |= tmp_psize;
    FLASH->CR &= SECTOR_MASK;
    FLASH->CR |= FLASH_CR_SER | i;
    FLASH->CR |= FLASH_CR_STRT;  
    /* Wait for last operation to be completed */
    while(FLASH_GetBank1Status()!=FLASH_COMPLETE){}
    /* if the erase operation is completed, disable the SER Bit */
    FLASH->CR &= (~FLASH_CR_SER);
    FLASH->CR &= SECTOR_MASK; 
	}
#endif
	return 0;
}

/**
 * @brief mbl_flash_write_word
 * @note 在指定位置开始以字为单位写入flash
 * @param srcAdr: write adr
 * @retval -1,error
 */
 	unsigned long adr=0;
	unsigned long data=0;
int mbl_flash_write_word(unsigned long srcAdr, unsigned long *buf, unsigned int num, unsigned long appAdr)
{
	int i=0;
	int t=0;

	if((srcAdr<appAdr)||(srcAdr+num*4)>(0X08000000+MBL_FLASH_SIZE))
		return -1;
	if (READ_BIT(FLASH->CR, FLASH_CR_LOCK))
		return -1;
	
	while(num>i)
	{
		/* Wait for last operation to be completed */
    while(FLASH_GetBank1Status()!=FLASH_COMPLETE){}
		adr = srcAdr+i*4;
		data = buf[i];
		i++;

#if (STM32F103x||STM32F030x)
		for(int j=0;j<2;j++)
		{
			/* Proceed to program the new data */
			SET_BIT(FLASH->CR, FLASH_CR_PG);
			/* Write data in the address */
			t=*(__IO unsigned short*)(adr+j*2);
			if(t==0xffff)
				*(__IO unsigned short*)(adr+j*2) = (unsigned short)(data>>(16*j));
			else
				return MBL_FLASH_ERASE_ERROR;
			if(*(__IO unsigned short*)(adr+j*2) != (unsigned short)(data>>(16*j)))
				return MBL_FLASH_WRITE_ERROR;
		}
#elif STM32F429x
		/* if the previous operation is completed, proceed to program the new data */
		FLASH->CR &= CR_PSIZE_MASK;
		FLASH->CR |= FLASH_PSIZE_WORD;
		FLASH->CR |= FLASH_CR_PG;
		t=*(__IO unsigned long*)(adr);
		if(t==0xffffffff) *(__IO unsigned long*)adr = data;		
		/* Wait for last operation to be completed */
		while(FLASH_GetBank1Status()!=FLASH_COMPLETE){}
		/* if the program operation is completed, disable the PG Bit */
		FLASH->CR &= (~FLASH_CR_PG);
		if(*(__IO unsigned long*)(adr) != (unsigned long)data)
				return MBL_FLASH_WRITE_ERROR;
#endif		
	}
	return num;
}

/**
 * @brief mbl_flash_lock_or
 * @note 解锁flash或上锁,
 * @param status 1,上锁;0,解锁
 * @retval status
 */
int mbl_flash_lock_or(unsigned char status)
{
	if(status==1)
	{
		SET_BIT(FLASH->CR, FLASH_CR_LOCK);
		return 1;
	}
	else if(status==0)
	{
		if (READ_BIT(FLASH->CR, FLASH_CR_LOCK))
		{
			/* Authorize the FLASH Registers access */
			WRITE_REG(FLASH->KEYR, FLASH_KEY1);
			WRITE_REG(FLASH->KEYR, FLASH_KEY2);		
		}
		return 0;
	}
	return -1;
}

